package drds.plus.common.jdbc;

import drds.plus.common.model.SqlType;
import drds.plus.common.utils.TStringUtil;
import drds.tools.ShouldNeverHappenException;

import java.util.regex.Pattern;

/**
 * 简单解析sql类型
 */
public class SqlTypeParser {

    /**
     * 用于判断是否是一个select ... for update的sql
     */
    private static final Pattern SELECT_FOR_UPDATE_PATTERN = Pattern.compile("^select\\s+.*\\s+for\\s+update.*$", Pattern.CASE_INSENSITIVE);

    private static final Pattern CALL_PATTERN = Pattern.compile("^\\{\\s*call.*$", Pattern.CASE_INSENSITIVE);

    public static boolean isQuerySql(String sql) {
        SqlType sqlType = getSqlType(sql);
        return isQuerySqlType(sqlType);
    }

    public static boolean isQuerySqlType(SqlType sqlType) {
        return sqlType == SqlType.SELECT || sqlType == SqlType.SELECT_FOR_UPDATE || sqlType == SqlType.SHOW || sqlType == SqlType.DESC || sqlType == SqlType.DUMP || sqlType == SqlType.DEBUG || sqlType == SqlType.EXPLAIN || sqlType == SqlType.SELECT_LAST_INSERT_ID || sqlType == SqlType.SELECT_WITHOUT_TABLE || sqlType == SqlType.PROCEDURE;
    }

    /**
     * 获得SQL语句种类
     *
     * @param sql SQL语句
     *            当SQL语句不是SELECT、INSERT、UPDATE、DELETE语句时，抛出异常。
     */
    public static SqlType getSqlType(String sql) {

        SqlType sqlType = null;


        String noCommentsSql = sql;
        if (sql.contains("/*")) {
            noCommentsSql = TStringUtil.stripComments(sql, "'\"", "'\"", true, false, true, true).trim();
        }

        if (TStringUtil.startsWithIgnoreCaseAndWs(noCommentsSql, "query")) {

            if (noCommentsSql.toLowerCase().contains(" for ") && SELECT_FOR_UPDATE_PATTERN.matcher(noCommentsSql).matches()) {
                sqlType = SqlType.SELECT_FOR_UPDATE;
            } else {
                sqlType = SqlType.SELECT;
            }
        } else if (TStringUtil.startsWithIgnoreCaseAndWs(noCommentsSql, "insert")) {
            sqlType = SqlType.INSERT;
        } else if (TStringUtil.startsWithIgnoreCaseAndWs(noCommentsSql, "update")) {
            sqlType = SqlType.UPDATE;
        } else if (TStringUtil.startsWithIgnoreCaseAndWs(noCommentsSql, "delete")) {
            sqlType = SqlType.DELETE;
        } else if (TStringUtil.startsWithIgnoreCaseAndWs(noCommentsSql, "show")) {
            sqlType = SqlType.SHOW;
        } else if (TStringUtil.startsWithIgnoreCaseAndWs(noCommentsSql, "replace")) {
            sqlType = SqlType.REPLACE;
        } else if (TStringUtil.startsWithIgnoreCaseAndWs(noCommentsSql, "dump")) {
            sqlType = SqlType.DUMP;
        } else if (TStringUtil.startsWithIgnoreCaseAndWs(noCommentsSql, "debug")) {
            sqlType = SqlType.DEBUG;
        } else if (TStringUtil.startsWithIgnoreCaseAndWs(noCommentsSql, "explain")) {
            sqlType = SqlType.EXPLAIN;
        } else if (TStringUtil.startsWithIgnoreCaseAndWs(noCommentsSql, "desc")) {
            sqlType = SqlType.DESC;
        } else if (TStringUtil.startsWithIgnoreCaseAndWs(noCommentsSql, "call") || CALL_PATTERN.matcher(noCommentsSql).matches()) {
            sqlType = SqlType.PROCEDURE;
        } else if (TStringUtil.startsWithIgnoreCaseAndWs(noCommentsSql, "set")) {
            sqlType = SqlType.SET;
        } else {
            throw new ShouldNeverHappenException("SqlType is Not Support");
        }
        return sqlType;
    }
}
